#include <iostream>
#include <opencv2/opencv.hpp>

extern "C" {
#include <libavformat/avformat.h>
#include <libavcodec/avcodec.h>
}

//const char *vdo_url = "rtsp://192.168.6.85:8557/h264";
const char *vdo_url = "E:\\source\\cmake_sample\\pack\\bin\\14_9_1.avi";

void dump_hex(const char *discript, const char *data, int size) {
  if (discript) {
    fprintf(stderr, "%s ", discript);
  }

  for (int i = 0; i < size; i++) {
    fprintf(stderr, "%02x ", (unsigned char)data[i]);
  }
  fprintf(stderr, "\n");
}

int main() {
  avformat_network_init(); // 初始化网络

  // 打开H.264文件
  AVFormatContext *formatContext = avformat_alloc_context();
  if (avformat_open_input(&formatContext, vdo_url, nullptr, nullptr) != 0) {
    std::cerr << "Could not open file." << std::endl;
    return -1;
  }

  // 查找视频流索引
  int videoStreamIndex = -1;
  for (unsigned int i = 0; i < formatContext->nb_streams; i++) {
    if (formatContext->streams[i]->codecpar->codec_type == AVMEDIA_TYPE_VIDEO) {
      videoStreamIndex = i;
      break;
    }
  }

  if (videoStreamIndex == -1) {
    std::cerr << "Could not find video stream." << std::endl;
    avformat_close_input(&formatContext);
    return -1;
  }

  AVCodecParameters *codecParameters = formatContext->streams[videoStreamIndex]->codecpar;

  // 查找解码器
  const AVCodec *codec = avcodec_find_decoder(codecParameters->codec_id);
  if (codec == nullptr) {
    std::cerr << "Could not find codec." << std::endl;
    avformat_close_input(&formatContext);
    return -1;
  }

  // 初始化解码器上下文
  AVCodecContext *codecContext = avcodec_alloc_context3(nullptr);
  if (avcodec_parameters_to_context(codecContext, codecParameters) != 0) {
    std::cerr << "Could not initialize codec context." << std::endl;
    avformat_close_input(&formatContext);
    avcodec_free_context(&codecContext);
    return -1;
  }

  if (avcodec_open2(codecContext, codec, nullptr) != 0) {
    std::cerr << "Could not open codec." << std::endl;
    avformat_close_input(&formatContext);
    avcodec_free_context(&codecContext);
    return -1;
  }

  AVPacket *packet = av_packet_alloc();

  // 读取数据包并解码
  while (av_read_frame(formatContext, packet) == 0) {
    if (packet->stream_index == videoStreamIndex) {
      AVFrame *frame = av_frame_alloc();

      // 解码视频帧

      int frameFinished = 0;
      if (avcodec_send_packet(codecContext, packet) == 0 &&
          avcodec_receive_frame(codecContext, frame) == 0) {
        // 在此处添加你的处理逻辑
        for (int i = 0; i < frame->nb_side_data; ++i) {
          AVFrameSideData *side_data = frame->side_data[i];
          if (side_data->type == AV_FRAME_DATA_SEI_UNREGISTERED) {
            // 此时 side_data->data 指向非注册的 SEI 数据；
//            uint8_t *sei_data = side_data->data;
//            int sei_size = side_data->size;
            dump_hex("sei info:", (const char *) side_data->data, side_data->size);

            unsigned char data[12] = {0};
            memcpy(data, side_data->data + side_data->size - 12, 12);
            printf("sei info: %d cm \n", ((int)data[4]<<8 | data[3]));
          }
        }

        // 使用OpenCV显示视频帧
//       printf("width %d, height %d.\n", codecContext->width, codecContext->height);
        if (codecContext->width > 0 && codecContext->height > 0) {
          cv::Mat image(codecContext->height, codecContext->width, CV_8UC3, frame->data[0]);
          if (!image.empty()) {
            cv::imshow("H.264 Video", image);
          }
        }
      }

      av_frame_free(&frame);
    }

    // 释放数据包
    av_packet_unref(packet);

    // 按下'q'键停止循环
    if (cv::waitKey(1) == 'q') {
      break;
    }
  }

  // 关闭文件和释放资源
  avformat_close_input(&formatContext);
  avcodec_free_context(&codecContext);
  av_packet_free(&packet);
  cv::destroyAllWindows();

  return 0;
}